"""
This is a mecurial implementation of the versioning API.
"""

from mercurial import commands, hg, ui
from sync.util import setting
import tempfile
import logging
import os.path as path
import os

log = logging.getLogger('sync.versioning.hg')
# =======
# = API =
# =======

def save(model,pk,data):
    """
    Saves the model instance.
    
    >>> from sync.models import ChangeSet
    >>> from django.core import serializers
    >>> changeset = ChangeSet.objects.get_or_create()
    >>> serializer = serializers.get_serializer('json')
    >>> data = serializer.serialize(changeset)
    >>> save(ChangeSet,changeset.pk,data)
    """
    repo, user_if = _get_repository()
    commands.update(user_if,repo)
    instance_file = open(path.join(_get_model_path(model),str(pk)),'w')
    instance_file.write(data)
    instance_file.close()
    commands.commit(user_if,repo,message='Saving %s %s' % (str(model),str(pk)),addremove=True)
    
def get(model,pk,version=None):
    """
    Gets the latest version of the specified model instance.
    
    >>> from sync.models import ChangeSet
    >>> from django.core import serializers
    >>> changeset = ChangeSet.objects.get_or_create()
    >>> data = serializers.serialize('json',changeset)
    >>> save(ChangeSet,changeset.pk,data)
    >>> retrieved_data = get(ChangeSet,changeset.pk).read()
    >>> retrieved = serializers.deserialize('json',retrieved_data)
    >>> changeset == retrieved
    True
    """
    repo, user_if = _get_repository()
    instance_path = path.join(_get_model_path(model),str(pk))
    if version:
        commands.update(user_if,repo,rev=version)
    else:
        commands.update(user_if,repo)
    if not path.exists(instance_path):
        raise model.DoesNotExist # return model specific exception if the instance is not in version control
    return open(instance_path,'r')

def get_versions(model,pk):
    """
    Gets the available versions of the specified model instance.
    """
    pass # TODO

def delete(model,pk):
    """
    Deletes the specified model instance.
    
    >>> from sync.models import ChangeSet
    >>> from django.core import serializers
    >>> changeset = ChangeSet.objects.get_or_create()
    >>> data = serializers.serialize('json',changeset)
    >>> save(ChangeSet,changeset.pk,data)
    >>> retrieved_data = get(ChangeSet,changeset.pk).read()
    >>> retrieved = serializers.deserialize('json',retrieved_data)
    >>> changeset == retrieved
    True
    >>> delete(ChangeSet,changeset.pk)
    >>> get(ChangeSet,changeset.pk)
    TODO: traceback statement to go here
    """
    repo, user_if = _get_repository()
    commands.update(user_if,repo)
    os.remove(path.join(_get_model_path(model),str(pk)))
    commands.commit(user_if,repo,message='Deleting %s %s' % (str(model),str(pk)),addremove=True)

# =====================
# = Private Functions =
# =====================

def _get_repo_path():
    """
    Gets the path for the repository directory.
    """
    return setting('SYNC_REPOSITORY') or path.join(tempfile.gettempdir(),'django-sync-repository')

def _get_repository():
    """
    Returns the repository.
    """
    user_if = ui.ui()
    return hg.repository(user_if,_get_repo_path()), user_if

def _get_model_path(model):
    """
    Gets or creates the model directory.
    """
    model_path = path.join(_get_repo_path(),model.__name__)
    if not path.exists(model_path):
        os.mkdir(model_path)
    return model_path

# =============
# = Test Hook =
# =============
def _test():
    import doctest
    doctest.testmod()
